欢迎光临专业集成电路测试网~~欢迎加入IC测试QQ群:111938408

专业IC测试网

当前位置: 网站主页 > 测试工程 >

[分享] 用 Python 实现 IC shmoo测试数据的可视化: 绘

时间:2023-10-20 20:40来源: Ryan 火红的兔子 作者:ictest8_edit 点击:

 

前言:
   ATE测试在集成电路的生产流程中发挥着至关重要的作用。测试一个晶圆(Wafer)时,会产生的大量数据需进行深入分析以评估电路的性能。在这之中,shmoo图的绘制是其中一种广为使用的分析方法。
   对于非专业人士,Shmoo图可能是一个陌生的术语。简而言之,它是一个展示两个变量间关系的二维图表。但Shmoo图远不止于此——在半导体测试中,它是一个高度信息化的可视化工具。通过Shmoo图,工程师可以直观地解析大量的数据,为质量控制、可靠性评估和决策提供关键信息。
 
 
烦恼如浮云遮月,写写脚本净心静气。
Python脚本目标:
    本脚本旨在将ATE测试数据转化为Excel中的Shmoo图,并对多个芯片数据进行叠加显示:
·     颜色化显示:每个芯片的测试数据(由0和1组成的二维数组,0代表Fail,1代表Pass)将被转化为颜色 。
·     统计学叠加:叠加多批次、多芯片的相同测试项的shmoo图,能够快速揭示某参数组合下的芯片特性。体现在excel的最左侧并进行了窗口冻结处理。
    
开门见山吧,测试结果如下:
 
 
代码如下:
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 20 20:27:33 2023

@author: ryan
"""

import openpyxl
from openpyxl.styles import PatternFill, Border, Side
import numpy as np

class ArrayDataset:
    """ArrayDataset 类:表示单个数据集并存储其相关信息"""
    
    def __init__(self, source_name, x_axis_name, y_axis_name, x_values, y_values):
        """构造函数初始化数据集的元信息和x,y轴的值"""
        self.source_name = source_name
        self.x_axis_name = x_axis_name
        self.y_axis_name = y_axis_name
        self.x_values = x_values
        self.y_values = y_values
        self.arrays = []

    def add_array(self, array_name, array_data):
        """向数据集添加一个数组"""
        self.arrays.append({"name": array_name, "data": array_data})


class ExcelGeneratorWithSpacing:
    """ExcelGeneratorWithSpacing 类:根据提供的数据集生成Excel文件"""

    # 设定颜色和边框样式
    RED_FILL = PatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid")
    GREEN_FILL = PatternFill(start_color="00FF00", end_color="00FF00", fill_type="solid")
    BORDER = Border(left=Side(border_style="thin", color="000000"),
                    right=Side(border_style="thin", color="000000"),
                    top=Side(border_style="thin", color="000000"),
                    bottom=Side(border_style="thin", color="000000"))
    
    def __init__(self, datasets):
        """构造函数初始化工作簿和工作表对象,并设置数据集"""
        self.datasets = datasets
        self.wb = openpyxl.Workbook()
        self.ws = self.wb.active

    def add_axes_and_labels(self, start_row, start_col, dataset):
        """在Excel中添加轴标签和数据集的x和y轴值"""
        
        # 添加x轴值
        for j, x_val in enumerate(dataset.x_values):
            cell = self.ws.cell(row=start_row + len(dataset.y_values) + 2, column=start_col + j)
            cell.value = x_val
        
        # 添加y轴值,注意y轴值是反转的
        for i, y_val in enumerate(reversed(dataset.y_values)):
            cell = self.ws.cell(row=start_row + i + 2, column=start_col - 1)
            cell.value = y_val
        
        # 添加x和y轴名字
        self.ws.cell(row=start_row + len(dataset.y_values) + 3, column=start_col + len(dataset.x_values) // 2).value = dataset.x_axis_name
        self.ws.cell(row=start_row + len(dataset.y_values) // 2 + 1, column=start_col - 2).value = dataset.y_axis_name


    def generate_excel(self, file_name):
        """根据数据集生成Excel文件"""
        
        start_row = 1  # 初始化开始行
        for dataset in self.datasets:
            start_col = 5  # 初始化开始列

            # 首先,计算2D数组的和
            summed_array = np.sum([array_info["data"] for array_info in dataset.arrays], axis=0)

            # 创建温暖的渐变颜色,基于零的数量
            max_value = int(summed_array.max())
            warm_gradient_colors = {
                i: f"{hex(255)[2:].zfill(2)}{hex(255 - int(i/max_value*255))[2:].zfill(2)}00"
                for i in range(1, max_value)
            }

            # 为summed_array添加颜色和值
            for i, row in enumerate(summed_array):
                for j, value in enumerate(row):
                    cell = self.ws.cell(row=start_row + i + 2, column=start_col + j)
                    if value == 0:
                        cell.fill = ExcelGeneratorWithSpacing.RED_FILL
                    elif value == len(dataset.arrays):
                        cell.fill = ExcelGeneratorWithSpacing.GREEN_FILL
                    else:
                        cell.value = summed_array[i,j]
                        cell.fill = PatternFill(start_color=warm_gradient_colors[cell.value], end_color=warm_gradient_colors[cell.value], fill_type="solid")
                    cell.border = ExcelGeneratorWithSpacing.BORDER
            
            # 添加轴和标签
            self.add_axes_and_labels(start_row, start_col, dataset)
            
            # 标注数据源名称
            source_name_cell = self.ws.cell(row=start_row + 2, column=1)
            source_name_cell.value = dataset.source_name          

            # 然后,添加单个数组
            start_col += len(summed_array[0]) + 5 + 3
            start_col_sum = start_col
            for array_info in dataset.arrays:
                array_data = array_info["data"]
                for i, row in enumerate(array_data):
                    for j, value in enumerate(row):
                        cell = self.ws.cell(row=start_row + i + 2, column=start_col + j)
                        if value == 0:
                            cell.fill = ExcelGeneratorWithSpacing.RED_FILL
                        else:
                            cell.fill = ExcelGeneratorWithSpacing.GREEN_FILL
                        cell.border = ExcelGeneratorWithSpacing.BORDER

                # 添加轴和标签
                self.add_axes_and_labels(start_row, start_col, dataset)
                
                # 标注die名称
                die_name_cell = self.ws.cell(row=start_row + 1, column=start_col)
                die_name_cell.value = array_info['name']
                
                start_col += len(array_data[0]) + 3

            # 调整下一个数据集的行开始位置
            start_row += len(dataset.y_values) + 7  # 7是为了考虑轴、标签和3行的间距

        # 调整列宽和行高以达到统一的单元格大小
        for col in self.ws.columns:
            adjusted_width = 4  # 设置固定宽度以达到统一的单元格大小
            self.ws.column_dimensions[col[0].column_letter].width = adjusted_width
            
        # 第一列固定。
        self.ws.column_dimensions['A'].width = 25
        
        for row in self.ws.rows:
            for cell in row:
                cell.alignment = openpyxl.styles.Alignment(horizontal='center', vertical='center')  # 水平和垂直居中对齐
            
            adjusted_height = 20  # 设置固定高度以达到统一的单元格大小
            self.ws.row_dimensions[row[0].row].height = adjusted_height

        # 最后保存文件
        self.wb.save(file_name)

if __name__ == "__main__":
    dataset1 = ArrayDataset(source_name="data_source_1",
                            x_axis_name="x1",
                            y_axis_name="y1",
                            x_values=list(range(1, 11)),
                            y_values=list(range(1, 11)))

    for i in range(5):
        data = np.random.randint(0, 2, size=(10, 10))
        dataset1.add_array(f"array_{i}", data)

    dataset2 = ArrayDataset(source_name="data_source_2",
                            x_axis_name="x2",
                            y_axis_name="y2",
                            x_values=list(range(1, 11)),
                            y_values=list(range(1, 11)))

    for i in range(3):
        data = np.random.randint(0, 2, size=(10, 10))
        dataset2.add_array(f"array_{i}", data)

    gen = ExcelGeneratorWithSpacing([dataset1, dataset2])
    gen.generate_excel("sample_output.xlsx")

    
    
    
if __name__ == "__main__":
    # 定义数据集使用的x和y值
    # 使用np.linspace在指定的两个限制值之间生成均匀分布的值。
    x_values = np.linspace(0.8, 1.2, 11).tolist()  # 定义x轴的值
    y_values = np.linspace(0.5, 2, 11).tolist()    # 定义y轴的值

    # 创建和填充数据集的函数
    # 此函数自动化创建一个填充有随机数组的数据集的过程。
    def generate_dataset(source_name, seed_value):
        # 设置随机数生成的种子,确保结果可复现。
        np.random.seed(seed_value)

        # 使用指定的名称、x和y值初始化一个新的数据集。
        dataset = ArrayDataset(source_name, "Vcoef", "Tcoef", x_values, y_values)

        # 定义生成数组过程中使用的常量。
        num_arrays = 10
        rows = 11
        cols = 11

        # 循环生成多个数组并将其添加到数据集中。
        for m in range(20):
            for _ in range(num_arrays):
                # 从填充有1的上三角矩阵开始。
                array = np.triu(np.ones((rows, cols)), k=0)

                # 根据指定的条件修改数组中的值。
                for i in range(rows):
                    for j in range(cols):
                        if i > j:
                            array[i, j] = 0
                        elif i < (j-1):
                            array[i, j] = 1
                        else:
                            # 随机选择0或1。
                            array[i, j] = np.random.choice([0, 1])
            # 将生成的数组添加到数据集。
            dataset.add_array(f"Die_{m+1}", array)
        return dataset

    # 使用前面定义的函数生成数据集。
    # 每个数据集都有一个唯一的源名称和种子值。
    dataset_bscan_01 = generate_dataset("FC_MBIST_XX_01", 12)
    dataset_bscan_02 = generate_dataset("FC_MBIST_XX_02", 42)

    # 使用生成的数据集初始化Excel生成器。
    # 数据集以列表的形式传递给生成器。
    generator = ExcelGeneratorWithSpacing([dataset_bscan_01, dataset_bscan_02, dataset_bscan_02])

    # 定义输出Excel文件的名称。
    output_file_name = "to_save_your_file.xlsx"

    # 调用函数生成Excel文件。
    generator.generate_excel(output_file_name)
    

如何使用
参考上述代码 if __name__ == "__main__":下的测试用例。构造了一系列假的11✖11的二维数组对应不同芯片的测试结果,元素的值为0/1.
    
数据输入:工具的效率始于有效的输入。因此,定义了ArrayDataset类,为你的测试数据提供了统一和直观的接口。这有助于简化数据的集成过程。
为何使用数据类?由于不同公司的ATE输出数据格式可能有所不同,定义此类可以确保我们的工具适用于多种格式。然而,用户可能还需简单处理ATE数据,以确保其符合我定义的输入格式。
 
 
初始化数据类:
    创建ArrayDataset对象时,你需要提供以下信息:
        source_name(测试项名称)
        x_axis_name(shmoo图的x轴名称或描述)
        y_axis_name(shmoo图的y轴名称或描述)
        x_values(x轴坐标刻度)
        y_values(y轴坐标范围)
 
示例:
x_values = np.linspace(0.8, 1.2, 11).tolist()
y_values = np.linspace(0.5, 2, 11).tolist()
dataset = ArrayDataset("FC_MBIST_XX_01", "Vcoef", "Tcoef", x_values, y_values)
 
一旦一个ArrayDataset 被初始化,你可以开始添加多个二维数组到这个数据集中。这些数组代表了同一个测试项不同芯片的测试结果。使用 add_array 方法可以轻松地完成这个任务。
示例:
dataset.add_array("Die_1", array_data)
假如你有三个测试项,则初始化三个dataset,传入脚本即可:
  # 使用生成的数据集初始化Excel生成器。
    # 数据集以列表的形式传递给生成器。
    generator = ExcelGeneratorWithSpacing([dataset_bscan_01, dataset_bscan_02, dataset_bscan_03])
 
你可能会问,为什么我不能直接传递我的二维数组呢?这里的关键在于组织。考虑到一个晶圆上可能有多达数百或数千的芯片,ArrayDataset 为我们提供了一个集中和组织这些数据的方法。更重要的是,它为你提供了一个简单的接口,你只需关心你的测试数据,不必担心如何在工具中处理它们。
 
 
下面继续展示不同尺寸的图示作为结束语:
 

 
 第1列为测试项名称
 
 
 

 
统计叠加的shmoo图之前做了窗口冻结,这样不同Die的图形可以与叠加图时刻做对比                  
 
 
 
 
 
 
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
用户名: 验证码: 点击我更换图片